#define _GNU_SOURCE 1
#include<t_stdio.h>
#include<t_file.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <sys/poll.h>
#include<fcntl.h>
#include<poll.h>
#define buffer_size 64 //缓冲区大小

int main(int argc , char * argv[])
{
    if(argc <= 2)//如果参数太少
    {
        printf("usage :%s ip_address port_number\n",basename(argv[0]));
        return 1;
    }

    const char * ip = argv[1] ;// 提取ip地址
    int port = atoi(argv[2]); //提取端口号

    struct sockaddr_in server_address ; //服务器地址
    bzero(&server_address ,sizeof(server_address));//清空
    server_address.sin_family = AF_INET;
    inet_pton(AF_INET , ip ,&server_address.sin_addr);//设置ip
    server_address.sin_port = htons(port); //设置端口号

    int sockfd = socket(PF_INET , SOCK_STREAM , 0 );//创建本地套接字
    assert(socket >= 0 ); //判错
    if(connect(sockfd , (struct sockaddr *)&server_address , sizeof(server_address)) < 0){//连接失败的话
        printf("connection failed...\n");
        close(sockfd);
        return 1;
    }


    struct pollfd fds[2];//创建pollfd结构类型数组，注册标准输入和sockfd文件描述符上的可读事件
    fds[0].fd = 0;
    fds[0].events = POLLIN ;//标准输入可读
    fds[0].revents = 0; //实际发生事件，由内核填充
    fds[1].fd = 0;
    fds[1].events = POLLIN | POLLRDHUP ;//标准输入可读
    fds[1].revents = 0; //实际发生事件，由内核填充

    char readbuf[buffer_size];//缓存数组
    int pipefd[2];//创建管道 ， 方便数据直接传入套接字sockfd
    int ret = pipe(pipefd) ;//创建管道
    assert(ret != -1);

    while (1){
        ret = poll(fds , 2 , -1); //最大被监听事件只有两个， 返回符合条件文件总数
        if(ret < 0){//如果监听发生错误
            printf("poll falied..\n");
            break;
        }
        if(fds[1].revents & POLLRDHUP){//假如发生了关闭对端连接
            printf("server close the connection..\n");
            break;
        }
        else if(fds[1].revents & POLLIN){//假如sockfd文件发生可读，则读取服务器传来数据
            memset(readbuf , '\0' , buffer_size);
            recv(fds[1].fd , readbuf , buffer_size -1 , 0);//接收数据
             if(ret <= 0){// 如果接收失败或对方关闭了连接
                printf("server close the connection..\n");
               break;
           }
            printf("%s\n",readbuf);//打印数据
        }
        if(fds[0].revents & POLLIN){//标准输入文件描述符可读，说明我们需要写入数据

        ret = splice(0 , NULL , pipefd[1] , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);//从标准输入写入数据到管道写端
        ret = splice(pipefd[0] , NULL , sockfd , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);//从管道读端将数据传输到sockfd
        printf("ok");
        }

    }
    close(sockfd);
    return 0;
}